//! 集群节点定义

use chrono::{DateTime, Utc};
use nacos_core::{ClusterNode, NodeState, NodeRole};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use uuid::Uuid;

/// 节点健康状态
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum NodeHealth {
    /// 健康
    Healthy,
    /// 不健康
    Unhealthy,
    /// 未知
    Unknown,
}

/// 集群节点信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClusterNodeInfo {
    /// 节点ID
    pub node_id: String,
    /// 节点IP
    pub ip: String,
    /// 节点端口
    pub port: u16,
    /// 节点状态
    pub state: NodeState,
    /// 节点角色
    pub role: NodeRole,
    /// 节点权重
    pub weight: u32,
    /// 上次心跳时间
    pub last_heartbeat: DateTime<Utc>,
    /// 加入时间
    pub join_time: DateTime<Utc>,
    /// 节点元数据
    pub metadata: HashMap<String, String>,
    /// 健康状态
    pub health: NodeHealth,
}

impl ClusterNodeInfo {
    /// 创建新的集群节点
    pub fn new<S: Into<String>>(ip: S, port: u16, weight: u32) -> Self {
        let now = Utc::now();
        Self {
            node_id: Uuid::new_v4().to_string(),
            ip: ip.into(),
            port,
            state: NodeState::Running,
            role: NodeRole::Follower,
            weight,
            last_heartbeat: now,
            join_time: now,
            metadata: HashMap::new(),
            health: NodeHealth::Healthy,
        }
    }

    /// 从ClusterNode创建
    pub fn from_cluster_node(node: ClusterNode) -> Self {
        Self {
            node_id: node.node_id,
            ip: node.ip,
            port: node.port,
            state: node.state,
            role: node.role,
            weight: 1,
            last_heartbeat: node.last_heartbeat,
            join_time: node.join_time,
            metadata: node.metadata,
            health: NodeHealth::Healthy,
        }
    }

    /// 转换为ClusterNode
    pub fn to_cluster_node(&self) -> ClusterNode {
        ClusterNode {
            node_id: self.node_id.clone(),
            ip: self.ip.clone(),
            port: self.port,
            state: self.state.clone(),
            role: self.role.clone(),
            last_heartbeat: self.last_heartbeat,
            join_time: self.join_time,
            metadata: self.metadata.clone(),
        }
    }

    /// 更新心跳时间
    pub fn update_heartbeat(&mut self) {
        self.last_heartbeat = Utc::now();
    }

    /// 检查节点是否健康
    pub fn is_healthy(&self, timeout_seconds: i64) -> bool {
        let now = Utc::now();
        let duration = now - self.last_heartbeat;
        duration.num_seconds() < timeout_seconds && self.health == NodeHealth::Healthy
    }

    /// 获取节点地址
    pub fn get_addr(&self) -> String {
        format!("{}:{}", self.ip, self.port)
    }

    /// 设置为领导者
    pub fn set_as_leader(&mut self) {
        self.role = NodeRole::Leader;
    }

    /// 设置为跟随者
    pub fn set_as_follower(&mut self) {
        self.role = NodeRole::Follower;
    }

    /// 是否为领导者
    pub fn is_leader(&self) -> bool {
        matches!(self.role, NodeRole::Leader)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_node_creation() {
        let node = ClusterNodeInfo::new("127.0.0.1", 8848, 1);
        
        assert!(!node.node_id.is_empty());
        assert_eq!(node.ip, "127.0.0.1");
        assert_eq!(node.port, 8848);
        assert_eq!(node.state, NodeState::Running);
        assert_eq!(node.role, NodeRole::Follower);
        assert_eq!(node.weight, 1);
        assert_eq!(node.health, NodeHealth::Healthy);
    }

    #[test]
    fn test_node_healthy_check() {
        let mut node = ClusterNodeInfo::new("127.0.0.1", 8848, 1);
        
        // 初始状态应该是健康的
        assert!(node.is_healthy(5));
        
        // 模拟超时
        node.last_heartbeat = Utc::now() - chrono::Duration::seconds(10);
        assert!(!node.is_healthy(5));
    }

    #[test]
    fn test_node_conversion() {
        let cluster_node = ClusterNode {
            node_id: "test-node".to_string(),
            ip: "127.0.0.1".to_string(),
            port: 8848,
            state: NodeState::Running,
            role: NodeRole::Leader,
            last_heartbeat: Utc::now(),
            join_time: Utc::now(),
            metadata: HashMap::new(),
        };
        
        let node_info = ClusterNodeInfo::from_cluster_node(cluster_node.clone());
        
        assert_eq!(node_info.node_id, "test-node");
        assert_eq!(node_info.ip, "127.0.0.1");
        assert_eq!(node_info.port, 8848);
        assert_eq!(node_info.state, NodeState::Running);
        assert_eq!(node_info.role, NodeRole::Leader);
        
        let converted_back = node_info.to_cluster_node();
        assert_eq!(converted_back.node_id, "test-node");
        assert_eq!(converted_back.ip, "127.0.0.1");
        assert_eq!(converted_back.port, 8848);
        assert_eq!(converted_back.state, NodeState::Running);
    }

    #[test]
    fn test_node_roles() {
        let mut node = ClusterNodeInfo::new("127.0.0.1", 8848, 1);
        
        assert!(!node.is_leader());
        
        node.set_as_leader();
        assert!(node.is_leader());
        
        node.set_as_follower();
        assert!(!node.is_leader());
    }
}